package com.zh.common.net.http

import android.text.TextUtils
import android.util.Log
import com.blankj.utilcode.util.LogUtils
import com.cj.webapp_Start.sp_network.requestEncrypt
import com.cj.webapp_Start.sp_network.responseDecrypt
import com.zh.common.BuildConfig
import com.zh.common.ktx.fromJsonObj
import com.zh.common.ktx.livePostValue
import com.zh.common.ktx.liveSetValue
import com.zh.common.utils.ZSpUtils
import com.zh.common.utils.ZipHelper
import com.zh.config.ZjConfig
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import okhttp3.ResponseBody.Companion.toResponseBody
import okio.Buffer
import org.json.JSONException
import org.json.JSONObject
import java.io.ByteArrayOutputStream
import java.nio.charset.Charset
import java.nio.charset.StandardCharsets

/**
 * @author :  zh
 * @description : 自定义拦截器
 * @date : 2019/5/6.
 */
class RequestIntercept : Interceptor {
    private val tag = "--okhttp--"

    override fun intercept(chain: Interceptor.Chain): Response {
        var request: Request = chain.request()
        val requestBuffer = Buffer()
        if (request.body != null) {
            request.body?.writeTo(requestBuffer)
        } else {
            LogUtils.wTag(tag, "request.body() == null")
        }

        //添加sessionId - 除去登录接口
        if (!TextUtils.isEmpty(ZSpUtils.getString(ZjConfig.sessionId))) {
            request = request.newBuilder()
                .addHeader("sessionId", ZSpUtils.getString(ZjConfig.sessionId)).build()
        }
        // 加密请求体
        val encryptedRequest = request.encryptBody()
        if (BuildConfig.DEBUG) {
            Log.d("request", "headers -> ${request.headers}")
        }

        //打印url信息
        /*LogUtils.wTag(
            tag,
            "Sending Request ->"
            , request.method
            , request.url
            , if (request.body != null) requestBuffer.readUtf8() else "null"
            , chain.connection()
            , request.headers
        )*/
        val t1 = System.nanoTime()
        val originalResponse = chain.proceed(encryptedRequest)
        val t2 = System.nanoTime()
        //打印响应时间
        /*LogUtils.wTag(
            tag,
            "Received response ->"
            , request.method
            , originalResponse.code, request.url, (t2 - t1) / 1e6
            , originalResponse.headers
        )*/

        //读取服务器返回的结果
        val responseBody = originalResponse.body
        val source = responseBody?.source()
        source?.apply {
            request(Long.MAX_VALUE) // Buffer the entire body.
            val buffer = buffer

            //获取content的压缩类型
            val encoding = originalResponse.headers["Content-Encoding"]
            val clone = buffer.clone()
            val bodyString: String

            //解析response content
            if (encoding != null && encoding.equals("gzip", ignoreCase = true)) { //content使用gzip压缩
                val outputStream = ByteArrayOutputStream()
                clone.writeTo(outputStream)
                val bytes = outputStream.toByteArray()
                bodyString = ZipHelper.instance.decompressForGzip(bytes).toString() //解压
                outputStream.close()
            } else if (encoding != null && encoding.equals(
                    "zlib",
                    ignoreCase = true
                )
            ) { //content使用zlib压缩
                val outputStream = ByteArrayOutputStream()
                clone.writeTo(outputStream)
                val bytes = outputStream.toByteArray()
                bodyString = ZipHelper.instance.decompressToStringForZlib(bytes).toString() //解压
                outputStream.close()
            } else { //content没有被压缩
                var charset = Charset.forName("UTF-8")
                val contentType = responseBody.contentType()
                if (contentType != null) {
                    charset = contentType.charset(charset)
                }
                bodyString = clone.readString(charset)
            }

//            LogUtils.wTag(tag, bodyString)

            //sessionId失效，去登录
            try {
                val jsonObject = JSONObject(bodyString)
                val code = jsonObject.getInt("code")
                if (code == 401) {
                    ZSpUtils.put(ZjConfig.sessionId, "")
                    //ARouter.getInstance().build(ZjConfig.LoginActivity).navigation();
                }
            } catch (e: JSONException) {
                e.printStackTrace()
                livePostValue("data", bodyString)
            }
        }
        return originalResponse.decryptBody()
    }

    private fun Request.encryptBody(): Request {
        if (!ZjConfig.isNeedEncrypt) return this
        val originalBody = body ?: return this // 无需加密空请求体
        // 读取原始请求体内容
        val buffer = Buffer()
        originalBody.writeTo(buffer)
        val rawData = buffer.readString(StandardCharsets.UTF_8)
        // 加密数据
        val encryptedData = rawData.requestEncrypt()
        // 构建新请求体
        val newBody = encryptedData.toRequestBody(originalBody.contentType())
        return newBuilder()
            .method(method, newBody)
            .build()
    }

    private fun Response.decryptBody(): Response {
        if (!ZjConfig.isNeedEncrypt) return this
        val originalBody = body ?: return this // 无需解密空响应体
        // 读取加密的响应体内容
        val encryptedData = originalBody.string()
        try {
            val jsonObject = JSONObject(encryptedData)
            if (!jsonObject.has("data") || jsonObject.opt("data") == null)// 无需解密空响应体
                return newBuilder()
                    .body(encryptedData.toResponseBody(originalBody.contentType()))
                    .build()
            // 解密数据
            val decryptedData = this.responseDecrypt(encryptedData)
            // 构建新响应体
            val newBody = decryptedData.toResponseBody(originalBody.contentType())
            return newBuilder()
                .body(newBody)
                .build()
        } catch (e: Exception) {
            return newBuilder()
                .body(encryptedData.toResponseBody(originalBody.contentType()))
                .build()
        }
    }
}